import 'dart:math' as math;
import 'dart:typed_data';
import 'dart:ui' as ui;
import 'dart:ui';

import 'package:animation_effect_demo/src/effects/text_animation_effect.dart';
import 'package:flutter/material.dart';

import '../../utils/image_util.dart';

import '../effect02.dart';
import '../effect03.dart';
import '../effect05.dart';
import '../effect07.dart';
import '../effect08.dart';
import '../effect10.dart';
import '../effect14.dart';
import '../effect15.dart';
import '../effect16.dart';
import '../effect20.dart';
import '../effect27.dart';
import '../effect30.dart';
import '../effect_template.dart';
import '../image_effect/static_image_animation_effect.dart';

enum EffectType {
  effect02,
  effect03,
  effect05,
  effect07,
  effect08,
  effect10,
  effect14,
  effect15,
  effect16,
  effect20,
  effect27,
  effect30,
  textEffect,
  staticImageEffect
}

///通用
const String animationPath = 'animation/';

///
const String flashAnimationPath = 'animation2/';


abstract class BaseEffect {
  EffectType get effectTyp;

  ///帧时间间隔(单位毫秒)
  int get frameDuration;

  ///横向点数和纵向点数，仅表示UI效果的点数，真实的点数要根据设备来换算
  Size get size;

  ///获取动画的全部侦内容
  Future<List<List<List<Color>>>> getFrames({EffectOperation? operation});

  factory BaseEffect(EffectType effectType) {
    if (effectType == EffectType.effect02) {
      return Effect02();
    } else if (effectType == EffectType.effect03) {
      return Effect03();
    } else if (effectType == EffectType.effect05) {
      return Effect05();
    } else if (effectType == EffectType.effect07) {
      return Effect07();
    } else if (effectType == EffectType.effect08) {
      return Effect08();
    } else if (effectType == EffectType.effect10) {
      return Effect10();
    } else if (effectType == EffectType.effect14) {
      return Effect14();
    } else if (effectType == EffectType.effect15) {
      return Effect15();
    } else if (effectType == EffectType.effect16) {
      return Effect16();
    } else if (effectType == EffectType.effect20) {
      return Effect20();
    } else if (effectType == EffectType.effect27) {
      return Effect27();
    } else if (effectType == EffectType.effect30) {
      return Effect30();
    } else if (effectType == EffectType.textEffect){
      return TextAnimationEffect();
    } else if (effectType == EffectType.staticImageEffect){
      return StaticImageAnimationEffect();
    }else {
      throw UnimplementedError(
        'The effect with effectId $effectType was not implemented',
      );
    }
  }
}



class RangeArgument {
  final int start;
  final int end;
  final int defaultValue;

  RangeArgument(this.start, this.end, this.defaultValue);
}

abstract class EditableAnimationEffect implements BaseEffect {
  ///颜色是否可编辑（修改颜色和增减颜色）
  bool get enableEditColor;

  ///是否固定颜色数量（可修改颜色值）
  bool get isFixedColorCount;

  ///预设颜色组合
  List<Color> get defaultColors;

  ///颜色数量范围（isFixedColorCount == false 时才生效）
  RangeArgument get colorCountRange =>
      throw UnimplementedError('colorCountRange has not implement');

  ///是否支持角度
  bool get enableAngle;

  ///角度范围
  RangeArgument get angleRange =>
      throw UnimplementedError('angleRange has not implement');

  ///是否支持速度
  bool get enableSpeed;

  ///速度范围
  RangeArgument get speedRange =>
      throw UnimplementedError('speedRange has not implement');

  ///是否支持密度
  bool get enableDensity;

  ///密度范围
  RangeArgument get densityRange =>
      throw UnimplementedError('densityRange has not implement');

  ///是否支持颜色宽度
  bool get enableColorWidth;

  ///颜色宽度范围
  RangeArgument get colorWidthRange =>
      throw UnimplementedError('colorWidthRange has not implement');

  List<Color> getColorList({required EffectOperation? effectOperation}) {
    List<Color> colorList;

    if (effectOperation?.colorList?.isEmpty ?? true) {
      colorList = defaultColors;
    } else {
      colorList = effectOperation!.colorList!;
    }
    return colorList;
  }


  int getAngle({required EffectOperation? effectOperation}){
    int angle = effectOperation?.angle ?? angleRange.defaultValue;

    if (angle < 0) {
      angle = 360 + angle;
    }

    return angle;
  }

  Size getRotateSize({required int angle}){
    double width = size.width;
    double height = size.height;
    double newWidth;
    double newHeight;
    double r = math.pi / 180 * angle;
    if (angle != 0) {
      ///计算旋转后的矩形大小
      newWidth =
          (width * math.cos(r).abs() + height * math.sin(r).abs()).round() + 3;
      newHeight =
          (height * math.cos(r).abs() + width * math.sin(r).abs()).round() + 3;
    } else {
      newWidth = width;
      newHeight = height;
    }

    return Size(newWidth,newHeight);
  }

  List<List<List<Color>>> getRotateFrames(
      List<List<List<Color>>> frames, {
        required int angle,
        required double newWidth,
        required double newHeight,
      }) {
    assert(angle >= 0);
    double width = size.width;
    double height = size.height;
    int offsetX = ((newWidth - width) * 0.5).round();
    int offsetY = ((newHeight - height) * 0.5).round();

    List<List<List<Color>>> angleFrames = [];
    double centerX = newWidth * 0.5;
    double centerY = newWidth * 0.5;
    double r = math.pi / 180 * angle;

    for (int i = 0; i < frames.length; i++) {
      List<List<Color>> frame = frames[i];
      List<List<Color>> angleFrame = [];

      ///通过逆运算获取原像素点颜色填充
      for (int j = offsetX; j < offsetX + width; j++) {
        List<Color> columns = [];
        for (int z = offsetY; z < offsetY + height; z++) {
          double newX = (j - centerX) * math.cos(2 * math.pi - r) +
              (centerY - z) * math.sin(2 * math.pi - r) +
              centerX;
          double newY = (j - centerX) * math.sin(2 * math.pi - r) +
              (z - centerY) * math.cos(2 * math.pi - r) +
              centerY;

          int posX = newX.round();
          int posY = newY.round();

          if (posX >= 0 && posX < newWidth && posY >= 0 && posY < newHeight) {
            columns.add(frame[posX][posY]);
          } else {
            print('angle:$angle,posX:$posX,posY:$posY');
            columns.add(const Color(0xFF000000));
          }
        }
        angleFrame.add(columns);
      }

      angleFrames.add(angleFrame);
    }
    return angleFrames;
  }

  @override
  int get frameDuration => 50;
}
